use crate::contract::coolink_sdk::P2PRPCServiceCallback;
use crate::imp::tonicrpc::kcptunnel::tunnel::{
    TonicServerStopKind, TunnelClientCreator, TunnelConfig, TunnelConn, TunnelConnectMsg,
    TunnelCreatorImp, TunnelPair, TunnelPairWithIp, TunnelStatus, URIInfo,
};
use crate::imp::tonicrpc::pairinlanmap;
use crate::imp::tonicrpc::tonictunnel::TonicTunnelCallback;
use tonic_inf::api::{
    ByteBufferData, ByteBufferRes, ByteBufferStart, SendContentData, SendContentRes,
    SendContentStart,
};

pub struct CustomTonicServerCallback {
    callback: Box<dyn P2PRPCServiceCallback>,
}

impl CustomTonicServerCallback {
    pub fn new(callback: Box<dyn P2PRPCServiceCallback>) -> Self {
        CustomTonicServerCallback { callback: callback }
    }
}

impl TonicTunnelCallback for CustomTonicServerCallback {
    // received tonic server created
    fn on_tonic_server_created(&self, creator: TunnelCreatorImp) {
        log::info!("on_tonic_server_created {:?}", creator);
        self.callback
            .on_p2prpc_server_created(creator.local_client_id.to_owned());
    }
    // received tonic server droped
    fn on_tonic_server_droped(&self, msg: TonicServerStopKind) {
        log::info!("on_tonic_server_droped {:?}", msg);
        self.callback.on_p2prpc_server_droped(msg.to_string());
    }
    // received kcp tunnel connect ready
    fn on_tunnel_connect_ready(&self, msg: TunnelConn) {
        log::info!("on_tunnel_connect_ready {:?}", msg);

        let TunnelConn {
            ice_agent: _,
            conn: _,
            remote_client_id,
            local_client_id,
            tunnel_id,
            cancel_tx: _,
            is_controlling,
            ekho_config: _,
        } = msg;
        self.callback.on_p2prpc_tunnel_created(
            tunnel_id,
            local_client_id,
            remote_client_id,
            is_controlling,
        );

        // FIX: add remote all in lan map
        pairinlanmap::remove_all_in_lan_map();
    }
    // received kcp tunnel connect destroy
    fn on_tunnel_connect_destroy(
        &self,
        tunnel_id: String,
        local_client_id: String,
        remote_client_id: String,
    ) {
        self.callback.on_p2prpc_tunnel_destroy(
            tunnel_id.clone(),
            local_client_id,
            remote_client_id,
        );

        pairinlanmap::remove_pair_in_lan_map_by_tunnel_id(tunnel_id.to_owned());
    }
    // received kcp tunnel state changged
    fn on_tunnel_state_changed(&self, msg: TunnelStatus) {
        let TunnelStatus {
            tunnel_id,
            sa_local_client_id,
            sa_remote_client_id,
            state,
            msg,
        } = msg;
        self.callback.on_p2prpc_tunnel_state_changed(
            tunnel_id,
            sa_local_client_id,
            sa_remote_client_id,
            state.to_string(),
            msg,
        );
    }
    // received kcp tunnel pair changged
    fn on_tunnel_pair_changed(&self, msg: TunnelPair) {
        let TunnelPair {
            tunnel_id,
            pair_local_client_id,
            pair_remote_client_id,
            remote_pair,
            mine_pair,
        } = msg.clone();
        self.callback.on_p2prpc_tunnel_pair_changed(
            tunnel_id,
            pair_local_client_id,
            pair_remote_client_id,
            mine_pair,
            remote_pair,
        );

        let pair_with_ip = TunnelPairWithIp::new(msg.to_owned());
        pairinlanmap::connected_pair_ip_map(pair_with_ip);
    }

    // received remote send content
    fn on_remote_content(&self, content: SendContentData) -> i64 {
        let SendContentData {
            id,
            tunnel_id,
            my_device_id: remote_client_id,
            remote_device_id: local_client_id,
            event,
            data,
            can_drop,
        } = content;
        self.callback.on_p2prpc_tunnel_rec_msg(
            tunnel_id,
            local_client_id,
            remote_client_id,
            id,
            event,
            data,
        );
        0
    }

    // received send content result
    fn on_send_content_result(&self, res: SendContentRes) -> i64 {
        let SendContentRes {
            id,
            tunnel_id,
            my_device_id: _,
            remote_device_id: _,
            code,
            msg,
        } = res;
        self.callback
            .on_p2prpc_send_msg_result(id, tunnel_id, code == 0, msg)
    }
    // received tonic content service start
    fn on_content_service_start(&self, info: SendContentStart) -> i64 {
        let SendContentStart {
            tunnel_id,
            my_device_id,
            remote_device_id,
            ..
        } = info;
        self.callback
            .on_text_tunnel_select_duplex(tunnel_id, my_device_id, remote_device_id)
    }

    // received tonic content service stop
    fn on_content_service_stop(&self, tunnel_id: String) -> i64 {
        self.callback.on_text_tunnel_cancel_duplex(tunnel_id)
    }

    // received remote send bytebuffer
    fn on_remote_bufferbuffer(&self, data: ByteBufferData) -> i64 {
        let ByteBufferData {
            id,
            tunnel_id,
            video_buffer,
            audio_buffer,
            can_drop,
        } = data;

        self.callback
            .on_p2prpc_tunnel_rec_bytebuffer(tunnel_id, id, video_buffer, audio_buffer)
    }

    // received send bytebuffer result
    fn on_send_bytebuffer_result(&self, res: ByteBufferRes) -> i64 {
        let ByteBufferRes {
            id,
            tunnel_id,
            code,
            msg,
        } = res;

        self.callback
            .on_p2prpc_send_bytebuffer_result(id, tunnel_id, code == 0, msg)
    }

    // received tonic bytebuffer service start
    fn on_bytebuffer_service_start(&self, start: ByteBufferStart) -> i64 {
        let ByteBufferStart {
            tunnel_id,
            my_device_id,
            remote_device_id,
            ..
        } = start;

        self.callback
            .on_bybebuf_tunnel_select_duplex(tunnel_id, my_device_id, remote_device_id)
    }

    // received tonic bytebuffer service stop
    fn on_bytebuffer_service_stop(&self, tunnel_id: String) -> i64 {
        self.callback.on_bybebuf_tunnel_cancel_duplex(tunnel_id)
    }
}
